﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Data;

namespace RaisingStudio.Data
{
    /// <summary>
    /// table.
    /// </summary>
    [DefinitionName("DataTable")]
    [Serializable]
    public class DataTable : System.Data.DataTable
    {
 #if USE_TYPEMANAGER
#else
        public static Dictionary<string, System.Type> WellKnownDataTypes;
        public static Dictionary<System.Type, string> WellKnownDataTypeNames;
        public static Dictionary<string, System.Data.DbType> WellKnownDbTypes;
        public static Dictionary<System.Data.DbType, string> WellKnownDbTypeNames;
#endif

        static DataTable()
        {
#if USE_TYPEMANAGER
#else
            #region WellKnownDataTypes
            WellKnownDataTypes = new Dictionary<string, System.Type>();
            WellKnownDataTypeNames = new Dictionary<System.Type, string>();
            WellKnownDataTypeNames.Add(typeof(short), "short");
            WellKnownDataTypes.Add("short", typeof(short));
            WellKnownDataTypes.Add("Short", typeof(short));
            WellKnownDataTypes.Add("SHORT", typeof(short));
            WellKnownDataTypes.Add("int16", typeof(short));
            WellKnownDataTypes.Add("Int16", typeof(short));
            WellKnownDataTypes.Add("INT16", typeof(short));

            WellKnownDataTypeNames.Add(typeof(int), "int");
            WellKnownDataTypes.Add("int", typeof(int));
            WellKnownDataTypes.Add("Int", typeof(int));
            WellKnownDataTypes.Add("INT", typeof(int));
            WellKnownDataTypes.Add("int32", typeof(int));
            WellKnownDataTypes.Add("Int32", typeof(int));
            WellKnownDataTypes.Add("INT32", typeof(int));

            WellKnownDataTypeNames.Add(typeof(long), "long");
            WellKnownDataTypes.Add("long", typeof(long));
            WellKnownDataTypes.Add("Long", typeof(long));
            WellKnownDataTypes.Add("LONG", typeof(long));
            WellKnownDataTypes.Add("int64", typeof(long));
            WellKnownDataTypes.Add("Int64", typeof(long));
            WellKnownDataTypes.Add("INT64", typeof(long));

            WellKnownDataTypeNames.Add(typeof(byte), "byte");
            WellKnownDataTypes.Add("byte", typeof(byte));
            WellKnownDataTypes.Add("Byte", typeof(byte));
            WellKnownDataTypes.Add("BYTE", typeof(byte));

            WellKnownDataTypeNames.Add(typeof(byte[]), "byte[]");
            WellKnownDataTypes.Add("byte[]", typeof(byte[]));
            WellKnownDataTypes.Add("Byte[]", typeof(byte[]));
            WellKnownDataTypes.Add("BYTE[]", typeof(byte[]));
            WellKnownDataTypes.Add("image", typeof(byte[]));
            WellKnownDataTypes.Add("Image", typeof(byte[]));
            WellKnownDataTypes.Add("IMAGE", typeof(byte[]));
            WellKnownDataTypes.Add("binary", typeof(byte[]));
            WellKnownDataTypes.Add("Binary", typeof(byte[]));
            WellKnownDataTypes.Add("BINARY", typeof(byte[]));

            WellKnownDataTypeNames.Add(typeof(bool), "bool");
            WellKnownDataTypes.Add("bool", typeof(bool));
            WellKnownDataTypes.Add("Bool", typeof(bool));
            WellKnownDataTypes.Add("BOOL", typeof(bool));
            WellKnownDataTypes.Add("boolean", typeof(bool));
            WellKnownDataTypes.Add("Boolean", typeof(bool));
            WellKnownDataTypes.Add("BOOLEAN", typeof(bool));

            WellKnownDataTypeNames.Add(typeof(float), "float");
            WellKnownDataTypes.Add("float", typeof(float));
            WellKnownDataTypes.Add("Float", typeof(float));
            WellKnownDataTypes.Add("FLOAT", typeof(float));
            WellKnownDataTypes.Add("single", typeof(float));
            WellKnownDataTypes.Add("Single", typeof(float));
            WellKnownDataTypes.Add("SINGLE", typeof(float));

            WellKnownDataTypeNames.Add(typeof(double), "double");
            WellKnownDataTypes.Add("double", typeof(double));
            WellKnownDataTypes.Add("Double", typeof(double));
            WellKnownDataTypes.Add("DOUBLE", typeof(double));

            WellKnownDataTypeNames.Add(typeof(decimal), "decimal");
            WellKnownDataTypes.Add("decimal", typeof(decimal));
            WellKnownDataTypes.Add("Decimal", typeof(decimal));
            WellKnownDataTypes.Add("DECIMAL", typeof(decimal));

            WellKnownDataTypeNames.Add(typeof(DateTime), "DateTime");
            WellKnownDataTypes.Add("datetime", typeof(DateTime));
            WellKnownDataTypes.Add("dateTime", typeof(DateTime));
            WellKnownDataTypes.Add("DateTime", typeof(DateTime));
            WellKnownDataTypes.Add("DATETIME", typeof(DateTime));

            WellKnownDataTypeNames.Add(typeof(Guid), "Guid");
            WellKnownDataTypes.Add("guid", typeof(Guid));
            WellKnownDataTypes.Add("Guid", typeof(Guid));
            WellKnownDataTypes.Add("GUID", typeof(Guid));

            WellKnownDataTypeNames.Add(typeof(string), "string");
            WellKnownDataTypes.Add("string", typeof(string));
            WellKnownDataTypes.Add("String", typeof(string));
            WellKnownDataTypes.Add("STRING", typeof(string));

            WellKnownDataTypeNames.Add(typeof(object), "object");
            WellKnownDataTypes.Add("object", typeof(object));
            WellKnownDataTypes.Add("Object", typeof(object));
            WellKnownDataTypes.Add("OBJECT", typeof(object));
            #endregion
            #region WellKnownDbTypes
            WellKnownDbTypes = new Dictionary<string, System.Data.DbType>();
            WellKnownDbTypeNames = new Dictionary<System.Data.DbType, string>();
            WellKnownDbTypes.Add("short", System.Data.DbType.Int16);
            WellKnownDbTypes.Add("Short", System.Data.DbType.Int16);
            WellKnownDbTypes.Add("SHORT", System.Data.DbType.Int16);
            WellKnownDbTypes.Add("int16", System.Data.DbType.Int16);
            WellKnownDbTypes.Add("Int16", System.Data.DbType.Int16);
            WellKnownDbTypes.Add("INT16", System.Data.DbType.Int16);
            WellKnownDbTypeNames.Add(System.Data.DbType.Int16, "short");

            WellKnownDbTypes.Add("int", System.Data.DbType.Int32);
            WellKnownDbTypes.Add("Int", System.Data.DbType.Int32);
            WellKnownDbTypes.Add("INT", System.Data.DbType.Int32);
            WellKnownDbTypes.Add("int32", System.Data.DbType.Int32);
            WellKnownDbTypes.Add("Int32", System.Data.DbType.Int32);
            WellKnownDbTypes.Add("INT32", System.Data.DbType.Int32);
            WellKnownDbTypeNames.Add(System.Data.DbType.Int32, "int");

            WellKnownDbTypes.Add("long", System.Data.DbType.Int64);
            WellKnownDbTypes.Add("Long", System.Data.DbType.Int64);
            WellKnownDbTypes.Add("LONG", System.Data.DbType.Int64);
            WellKnownDbTypes.Add("int64", System.Data.DbType.Int64);
            WellKnownDbTypes.Add("Int64", System.Data.DbType.Int64);
            WellKnownDbTypes.Add("INT64", System.Data.DbType.Int64);
            WellKnownDbTypeNames.Add(System.Data.DbType.Int64, "long");

            WellKnownDbTypes.Add("byte", System.Data.DbType.Byte);
            WellKnownDbTypes.Add("Byte", System.Data.DbType.Byte);
            WellKnownDbTypes.Add("BYTE", System.Data.DbType.Byte);
            WellKnownDbTypeNames.Add(System.Data.DbType.Byte, "byte");

            WellKnownDbTypes.Add("byte[]", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("Byte[]", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("BYTE[]", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("image", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("Image", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("IMAGE", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("binary", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("Binary", System.Data.DbType.Binary);
            WellKnownDbTypes.Add("BINARY", System.Data.DbType.Binary);
            WellKnownDbTypeNames.Add(System.Data.DbType.Binary, "byte[]");

            WellKnownDbTypes.Add("bool", System.Data.DbType.Boolean);
            WellKnownDbTypes.Add("Bool", System.Data.DbType.Boolean);
            WellKnownDbTypes.Add("BOOL", System.Data.DbType.Boolean);
            WellKnownDbTypes.Add("boolean", System.Data.DbType.Boolean);
            WellKnownDbTypes.Add("Boolean", System.Data.DbType.Boolean);
            WellKnownDbTypes.Add("BOOLEAN", System.Data.DbType.Boolean);
            WellKnownDbTypeNames.Add(System.Data.DbType.Boolean, "bool");

            WellKnownDbTypes.Add("float", System.Data.DbType.Single);
            WellKnownDbTypes.Add("Float", System.Data.DbType.Single);
            WellKnownDbTypes.Add("FLOAT", System.Data.DbType.Single);
            WellKnownDbTypes.Add("single", System.Data.DbType.Single);
            WellKnownDbTypes.Add("Single", System.Data.DbType.Single);
            WellKnownDbTypes.Add("SINGLE", System.Data.DbType.Single);
            WellKnownDbTypeNames.Add(System.Data.DbType.Single, "float");

            WellKnownDbTypes.Add("double", System.Data.DbType.Double);
            WellKnownDbTypes.Add("Double", System.Data.DbType.Double);
            WellKnownDbTypes.Add("DOUBLE", System.Data.DbType.Double);
            WellKnownDbTypeNames.Add(System.Data.DbType.Double, "double");

            WellKnownDbTypes.Add("decimal", System.Data.DbType.Decimal);
            WellKnownDbTypes.Add("Decimal", System.Data.DbType.Decimal);
            WellKnownDbTypes.Add("DECIMAL", System.Data.DbType.Decimal);
            WellKnownDbTypeNames.Add(System.Data.DbType.Decimal, "decimal");

            WellKnownDbTypes.Add("datetime", System.Data.DbType.DateTime);
            WellKnownDbTypes.Add("dateTime", System.Data.DbType.DateTime);
            WellKnownDbTypes.Add("DateTime", System.Data.DbType.DateTime);
            WellKnownDbTypes.Add("DATETIME", System.Data.DbType.DateTime);
            WellKnownDbTypeNames.Add(System.Data.DbType.DateTime, "DateTime");

            WellKnownDbTypes.Add("guid", System.Data.DbType.Guid);
            WellKnownDbTypes.Add("Guid", System.Data.DbType.Guid);
            WellKnownDbTypes.Add("GUID", System.Data.DbType.Guid);
            WellKnownDbTypeNames.Add(System.Data.DbType.Guid, "Guid");

            WellKnownDbTypes.Add("string", System.Data.DbType.String);
            WellKnownDbTypes.Add("String", System.Data.DbType.String);
            WellKnownDbTypes.Add("STRING", System.Data.DbType.String);
            WellKnownDbTypeNames.Add(System.Data.DbType.String, "string");

            WellKnownDbTypes.Add("object", System.Data.DbType.Object);
            WellKnownDbTypes.Add("Object", System.Data.DbType.Object);
            WellKnownDbTypes.Add("OBJECT", System.Data.DbType.Object);
            WellKnownDbTypeNames.Add(System.Data.DbType.Object, "object");
            #endregion
#endif
        }

        #region static member
        /// <summary>
        /// Gets Wellknown Type.
        /// </summary>
        /// <param name="name">Type name.</param>
        /// <returns>Type.</returns>
        public static System.Type GetWellKnownDataType(string name)
        {
#if USE_TYPEMANAGER
            return RaisingStudio.Common.Reflection.TypeManager.GetWellKnownDataType(name);
#else
            if (WellKnownDataTypes.ContainsKey(name))
            {
                return WellKnownDataTypes[name];
            }
            return null;
#endif
        }
        
        /// <summary>
        /// Gets datatable Type.
        /// </summary>
        /// <param name="dataTable">Datatable.</param>
        /// <param name="typeName">Type name.</param>
        /// <returns>datatable Type.</returns>
        public static System.Type GetDataTableType(System.Data.DataTable dataTable, System.Type type, string typeName)
        {
#if USE_TYPEMANAGER
            return RaisingStudio.Reflection.TypeManager.GetType(dataTable, typeName);
#else
            System.Type dataTableType;
            System.Reflection.Assembly assembly;
            if (typeName.IndexOf(",") >= 0)
            {
                string[] names = typeName.Split(',');
                assembly = System.Reflection.Assembly.LoadFrom(names[0]);
                typeName = names[1];
            }
            else
            {
                assembly = type.Assembly;
            }

            dataTableType = assembly.GetType(typeName);
            return dataTableType;
#endif
        }

        /// <summary>
        /// Initialize.
        /// </summary>
        /// <param name="dataTable">table.</param>
        /// <param name="xmlElement">xml element.</param>
        /// <param name="system">Use System.Data.DataColumn as Data column.</param>
        public static void InitDataTable(System.Data.DataTable dataTable, System.Type type, System.Xml.XmlElement xmlElement, bool system)
        {
            if (xmlElement != null)
            {
                #region Sets table column
                List<System.Data.DataColumn> primaryKeyList = new List<System.Data.DataColumn>(dataTable.PrimaryKey);
                foreach (System.Xml.XmlNode childXmlNode in xmlElement)
                {
                    if (childXmlNode is System.Xml.XmlElement)
                    {
                        System.Xml.XmlElement childXmlElement = childXmlNode as System.Xml.XmlElement;
                        if (childXmlElement.Name == "DataColumn")
                        {
                            string columnName = childXmlElement.Attributes["ColumnName"].Value.Trim();
                            SetupDataColumn(dataTable, system, primaryKeyList, childXmlElement, columnName);
                        }
                    }
                }
                #endregion
                SetupDataTable(dataTable, type, xmlElement, system, primaryKeyList);
            }
            else
            {
                // TODO: use [Attribute] to define Table/Column mapping.
                List<System.Data.DataColumn> primaryKeyList = new List<System.Data.DataColumn>(dataTable.PrimaryKey);
                // Columns
                PropertyInfo[] properties = type.GetProperties();
                if ((properties != null) && (properties.Length > 0))
                {
                    foreach (PropertyInfo propertyInfo in properties)
                    {
                        string columnName = propertyInfo.Name;
                        DataColumnAttribute dataColumnAttribute = Attribute.GetCustomAttribute(propertyInfo, typeof(DataColumnAttribute)) as DataColumnAttribute;
                        if (dataColumnAttribute != null)
                        {
                            if (!string.IsNullOrEmpty(dataColumnAttribute.ColumnName))
                            {
                                columnName = dataColumnAttribute.ColumnName;
                            }
                            SetupDataColumn(dataTable, system, primaryKeyList, propertyInfo, dataColumnAttribute, columnName);
                        }
                    }
                }
                SetupDataTable(dataTable, type, xmlElement, system, primaryKeyList);
            }
        }

        public static void InitDataTable(System.Data.DataTable dataTable, System.Type type, System.Xml.XmlElement xmlElement, string[] columns, bool system)
        {
            if (xmlElement != null)
            {
                #region Sets table column
                List<System.Data.DataColumn> primaryKeyList = new List<System.Data.DataColumn>(dataTable.PrimaryKey);
                foreach (System.Xml.XmlNode childXmlNode in xmlElement)
                {
                    if (childXmlNode is System.Xml.XmlElement)
                    {
                        System.Xml.XmlElement childXmlElement = childXmlNode as System.Xml.XmlElement;
                        if (childXmlElement.Name == "DataColumn")
                        {
                            string columnName = childXmlElement.Attributes["ColumnName"].Value.Trim();
                            if (ColumnInColumns(columnName, columns))
                            {
                                SetupDataColumn(dataTable, system, primaryKeyList, childXmlElement, columnName);
                            }
                        }
                    }
                }
                #endregion
                SetupDataTable(dataTable, type, xmlElement, system, primaryKeyList);
            }
            else
            {
                // TODO: use [Attribute] to define Table/Column mapping.
                List<System.Data.DataColumn> primaryKeyList = new List<System.Data.DataColumn>(dataTable.PrimaryKey);
                // Columns
                PropertyInfo[] properties = type.GetProperties();
                if ((properties != null) && (properties.Length > 0))
                {
                    foreach (PropertyInfo propertyInfo in properties)
                    {
                        string columnName = propertyInfo.Name;
                        DataColumnAttribute dataColumnAttribute = Attribute.GetCustomAttribute(propertyInfo, typeof(DataColumnAttribute)) as DataColumnAttribute;
                        if (dataColumnAttribute != null)
                        {
                            if (!string.IsNullOrEmpty(dataColumnAttribute.ColumnName))
                            {
                                columnName = dataColumnAttribute.ColumnName;
                            }
                        }
                        if (ColumnInColumns(columnName, columns))
                        {
                            SetupDataColumn(dataTable, system, primaryKeyList, propertyInfo, dataColumnAttribute, columnName);
                        }
                    }
                }
                SetupDataTable(dataTable, type, xmlElement, system, primaryKeyList);
            }
        }

        private static void SetupDataColumn(System.Data.DataTable dataTable, bool system, List<System.Data.DataColumn> primaryKeyList, PropertyInfo propertyInfo, DataColumnAttribute dataColumnAttribute, string columnName)
        {
            // TODO: use [Attribute] to define Table/Column mapping.
            // Create column 。
            if (dataColumnAttribute != null)
            {
                System.Data.DataColumn dataColumn;
                if (system)
                {
                    dataColumn = new System.Data.DataColumn();
                }
                else
                {
                    dataColumn = new RaisingStudio.Data.DataColumn();
                }

                // Sets Column name.
                dataColumn.ColumnName = columnName;
                #region other property
                dataColumn.AllowDBNull = dataColumnAttribute.AllowDBNull;
                dataColumn.AutoIncrement = dataColumnAttribute.AutoIncrement;
                #endregion
                System.Data.DbType dbType = DbType.String;
                if (!dataColumnAttribute.IsDbTypeNull)
                {
                    dbType = dataColumnAttribute.DbType;
                }
                else
                {
                    Type propertyType = propertyInfo.PropertyType;
                    if (propertyType.IsGenericType)
                    {
                        if (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            Type argumentsType = propertyType.GetGenericArguments()[0];
                            if (argumentsType.IsEnum)
                            {
                                dbType = System.Data.DbType.String;
                            }
                            else
                            {
                                dbType = GetDefaultDbType(argumentsType);
                            }
                        }
                    }
                    else if (propertyType.IsEnum)
                    {
                        dbType = System.Data.DbType.Int32;
                    }
                    else
                    {
                        dbType = GetDefaultDbType(propertyType);
                    }
                }
                string dataType = GetWellKnownDbTypeName(dbType);
                Type type = GetWellKnownDataType(dataType.Trim());
                if (dataType != null)
                {
                    dataColumn.DataType = type;
                }
                else
                {
                    dataColumn.DataType = type;
                }


                #region process primary key
                if ((dataColumnAttribute != null) && (dataColumnAttribute.IsPrimaryKey))
                {
                    primaryKeyList.Add(dataColumn);
                }
                #endregion
                // Add column 。
                dataTable.Columns.Add(dataColumn);
            }
        }

        private static DbType GetDefaultDbType(Type type)
        {
            return GetWellKnownDbType(GetWellKnownDataTypeName(type));
        }

        public static string GetWellKnownDataTypeName(System.Type type)
        {
            if (WellKnownDataTypeNames.ContainsKey(type))
            {
                return WellKnownDataTypeNames[type];
            }
            return type.ToString();
        }

        /// <summary>
        /// Gets Wellknown Type.
        /// </summary>
        /// <param name="dataType">data Type name.</param>
        /// <returns>Data type.</returns>
        public static System.Data.DbType GetWellKnownDbType(string dbType)
        {
            return WellKnownDbTypes[dbType.Trim()];
        }

        public static string GetWellKnownDbTypeName(System.Data.DbType dbType)
        {
            if (WellKnownDbTypeNames.ContainsKey(dbType))
            {
                return WellKnownDbTypeNames[dbType];
            }
            return dbType.ToString();
        }

        private static bool ColumnInColumns(string columnName, string[] columns)
        {
            for (int i = 0; i < columns.Length; i++)
            {
                if (columns[i] == columnName)
                {
                    return true;
                }
            }
            return false;
        }

        private static void SetupDataTable(System.Data.DataTable dataTable, System.Type type, System.Xml.XmlElement xmlElement, bool system, List<System.Data.DataColumn> primaryKeyList)
        {
            #region Sets primary key
            if (primaryKeyList.Count > dataTable.PrimaryKey.Length)
            {
                System.Data.DataColumn[] primaryKeys = new System.Data.DataColumn[primaryKeyList.Count];
                primaryKeyList.CopyTo(primaryKeys);
                if ((dataTable.PrimaryKey == null) || (dataTable.PrimaryKey.Length == 0))
                {
                    if (primaryKeys.Length > 0)
                    {
                        System.Data.UniqueConstraint uniqueConstraint = new System.Data.UniqueConstraint(primaryKeys, true);
                        dataTable.Constraints.Add(uniqueConstraint);
                    }
                }
                dataTable.PrimaryKey = primaryKeys;
            }
            #endregion

            if (xmlElement != null)
            {
                #region include Relation
                if (xmlElement.Attributes["IncludeDefinition"] != null)
                {
                    // Has include relation.
                    string includeDefinitionName = xmlElement.Attributes["IncludeDefinition"].Value.Trim();

                    if (xmlElement.Attributes["IncludeType"] != null)
                    {
                        string includeTypeName = xmlElement.Attributes["IncludeType"].Value.Trim();
                        System.Type dataTableType = GetDataTableType(dataTable, type, includeTypeName);

                        InitDataTable(dataTable, dataTableType, includeDefinitionName, system);
                    }
                    else
                    {
                        InitDataTable(dataTable, type, includeDefinitionName, system);
                    }
                }
                #endregion

                #region Sets table name
                if (xmlElement.Attributes["TableName"] != null)
                {
                    string tableName = xmlElement.Attributes["TableName"].Value.Trim();
                    // Sets table name.
                    dataTable.TableName = tableName;
                }
                #endregion

                #region other property
                if (xmlElement.Attributes["CaseSensitive"] != null)
                {
                    dataTable.CaseSensitive = bool.Parse(xmlElement.Attributes["CaseSensitive"].Value);
                }
                if (xmlElement.Attributes["DisplayExpression"] != null)
                {
                    dataTable.DisplayExpression = xmlElement.Attributes["DisplayExpression"].Value;
                }
                if (xmlElement.Attributes["Locale"] != null)
                {
                    dataTable.Locale = new System.Globalization.CultureInfo(xmlElement.Attributes["Locale"].Value);
                }
                if (xmlElement.Attributes["MinimumCapacity"] != null)
                {
                    dataTable.MinimumCapacity = int.Parse(xmlElement.Attributes["MinimumCapacity"].Value);
                }
                if (xmlElement.Attributes["Prefix"] != null)
                {
                    dataTable.Prefix = xmlElement.Attributes["Prefix"].Value;
                }

#if (PocketPC || Smartphone || WindowsCE)
#else
                if (xmlElement.Attributes["RemotingFormat"] != null)
                {
                	dataTable.RemotingFormat = (System.Data.SerializationFormat)Enum.Parse(typeof(System.Data.SerializationFormat), xmlElement.Attributes["RemotingFormat"].Value, false);
            	}
#endif
                #endregion
            }
            else
            {
                string tableName = type.Name;
                DataTableAttribute dataTableAttribute = Attribute.GetCustomAttribute(type, typeof(DataTableAttribute)) as DataTableAttribute;
                if (dataTableAttribute != null)
                {
                    if (!string.IsNullOrEmpty(dataTableAttribute.TableName))
                    {
                        tableName = dataTableAttribute.TableName;
                    }
                }
                dataTable.TableName = tableName;
            }
        }

        private static void SetupDataColumn(System.Data.DataTable dataTable, bool system, List<System.Data.DataColumn> primaryKeyList, System.Xml.XmlElement childXmlElement, string columnName)
        {
            // Create column 。
            System.Data.DataColumn dataColumn;
            if (system)
            {
                dataColumn = new System.Data.DataColumn();
            }
            else
            {
                dataColumn = new RaisingStudio.Data.DataColumn();
            }

            // Sets Column name.
            dataColumn.ColumnName = columnName;
            // Sets Data type.
            if (childXmlElement.Attributes["DataType"] != null)
            {
                dataColumn.DataType = GetWellKnownDataType(childXmlElement.Attributes["DataType"].Value.Trim());
            }
            #region other property 
            if (childXmlElement.Attributes["AllowDBNull"] != null)
            {
                dataColumn.AllowDBNull = bool.Parse(childXmlElement.Attributes["AllowDBNull"].Value);
            }
            if (childXmlElement.Attributes["AutoIncrement"] != null)
            {
                dataColumn.AutoIncrement = bool.Parse(childXmlElement.Attributes["AutoIncrement"].Value);
                if (dataColumn.AutoIncrement)
                {
                    if (childXmlElement.Attributes["AutoIncrementSeed"] != null)
                    {
                        dataColumn.AutoIncrementSeed = long.Parse(childXmlElement.Attributes["AutoIncrementSeed"].Value);
                    }
                    if (childXmlElement.Attributes["AutoIncrementStep"] != null)
                    {
                        dataColumn.AutoIncrementStep = long.Parse(childXmlElement.Attributes["AutoIncrementStep"].Value);
                    }
                }
            }
            if (childXmlElement.Attributes["Caption"] != null)
            {
                dataColumn.Caption = childXmlElement.Attributes["Caption"].Value;
            }
            if (childXmlElement.Attributes["ColumnMapping"] != null)
            {
                dataColumn.ColumnMapping = (System.Data.MappingType)Enum.Parse(typeof(System.Data.MappingType), childXmlElement.Attributes["ColumnMapping"].Value, false);
            }
            if (childXmlElement.Attributes["DateTimeMode"] != null)
            {
                dataColumn.DateTimeMode = (System.Data.DataSetDateTime)Enum.Parse(typeof(System.Data.DataSetDateTime), childXmlElement.Attributes["DateTimeMode"].Value, false);
            }
            if (childXmlElement.Attributes["Expression"] != null)
            {
                dataColumn.Expression = childXmlElement.Attributes["Expression"].Value;
            }
            if (childXmlElement.Attributes["MaxLength"] != null)
            {
                dataColumn.MaxLength = int.Parse(childXmlElement.Attributes["MaxLength"].Value);
            }
            if (childXmlElement.Attributes["Prefix"] != null)
            {
                dataColumn.Prefix = childXmlElement.Attributes["Prefix"].Value;
            }
            if (childXmlElement.Attributes["ReadOnly"] != null)
            {
                dataColumn.ReadOnly = bool.Parse(childXmlElement.Attributes["ReadOnly"].Value);
            }
            if (childXmlElement.Attributes["Unique"] != null)
            {
                dataColumn.Unique = bool.Parse(childXmlElement.Attributes["Unique"].Value);
            }
            #endregion
            #region process primary key 
            if (childXmlElement.Attributes["PrimaryKey"] != null)
            {
                bool primaryKey = bool.Parse(childXmlElement.Attributes["PrimaryKey"].Value);
                if (primaryKey)
                {
                    primaryKeyList.Add(dataColumn);
                }
            }
            #endregion
            // Add column 。
            dataTable.Columns.Add(dataColumn);
        }

        /// <summary>
        /// Initialize.
        /// </summary>
        /// <param name="dataTable">table.</param>
        /// <param name="type">Type.</param>
        public static void InitDataTable(System.Data.DataTable dataTable, System.Type type)
        {
            System.Xml.XmlElement xmlElement = DefinitionNameAttribute.LoadXmlDocument(type);
            InitDataTable(dataTable, type, xmlElement, false);
        }

        /// <summary>
        /// Initialize.
        /// </summary>
        /// <param name="dataTable">table.</param>
        /// <param name="type">Type.</param>
        /// <param name="system">Use System.Data.DataColumn as Data column.</param>
        public static void InitDataTable(System.Data.DataTable dataTable, System.Type type, bool system)
        {
            System.Xml.XmlElement xmlElement = DefinitionNameAttribute.LoadXmlDocument(type);
            InitDataTable(dataTable, type, xmlElement, system);
        }

        /// <summary>
        /// Initialize.
        /// </summary>
        /// <param name="dataTable">table.</param>
        /// <param name="type">Type.</param>
        /// <param name="name">name.</param>
        public static void InitDataTable(System.Data.DataTable dataTable, System.Type type, string name)
        {
            System.Xml.XmlElement xmlElement = DefinitionNameAttribute.LoadXmlDocument(type, name);
            InitDataTable(dataTable, type, xmlElement, false);
        }

        /// <summary>
        /// Initialize.
        /// </summary>
        /// <param name="dataTable">table.</param>
        /// <param name="type">Type.</param>
        /// <param name="name">name.</param>
        /// <param name="system">Use System.Data.DataColumn as Data column.</param>
        public static void InitDataTable(System.Data.DataTable dataTable, System.Type type, string name, bool system)
        {
            System.Xml.XmlElement xmlElement = DefinitionNameAttribute.LoadXmlDocument(type, name);
            InitDataTable(dataTable, type, xmlElement, system);
        }


        /// <summary>
        /// Copy data into data object.
        /// </summary>
        /// <param name="dataRow">Datarow.</param>
        /// <param name="dataObject">Data object.</param>
        /// <returns>Count of copyed.</returns>
        public static int CopyTo(System.Data.DataRow dataRow, object dataObject)
        {
            System.Type dataObjectType = dataObject.GetType();
            int count = 0;
            foreach (System.Data.DataColumn dataColumn in dataRow.Table.Columns)
            {
                System.Reflection.PropertyInfo propertyInfo = dataObjectType.GetProperty(dataColumn.ColumnName);
                if (propertyInfo != null)
                {
                    object value = dataRow[dataColumn];
                    if (value == System.DBNull.Value)
                    {
                        propertyInfo.SetValue(dataObject, null, null);
                    }
                    else
                    {
                        // TODO: convert.
                        propertyInfo.SetValue(dataObject, value, null);
                    }
                    count++;
                }
            }
            return count;
        }

        /// <summary>
        /// Copy from data object.
        /// </summary>
        /// <param name="dataRow">Datarow.</param>
        /// <param name="dataObject">Data object.</param>
        /// <returns>Count of copyed.</returns>
        public static int CopyFrom(System.Data.DataRow dataRow, object dataObject)
        {
            System.Type dataObjectType = dataObject.GetType();
            int count = 0;
            foreach (System.Data.DataColumn dataColumn in dataRow.Table.Columns)
            {
                System.Reflection.PropertyInfo propertyInfo = dataObjectType.GetProperty(dataColumn.ColumnName);
                if (propertyInfo != null)
                {
                    object value = propertyInfo.GetValue(dataObject, null);
                    if (value == null)
                    {
                        dataRow[dataColumn] = System.DBNull.Value;
                    }
                    else
                    {
                        dataRow[dataColumn] = value;
                    }
                    count++;
                }
            }
            return count;
        }
        #endregion
     
        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        public DataTable()
        {
        }

#if (PocketPC || Smartphone || WindowsCE)
#else
        protected DataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
        {
        }
#endif

        /// <summary>
        /// Constructor
        /// </summary>
        protected DataTable(bool clonal)
        {
            this.clonal = clonal;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="type">Type.</param>
        public DataTable(System.Type type)
        {
            this.BeginInit();
            InitDataTable(this, type);
            this.EndInit();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="type">Type.</param>
        /// <param name="name">name.</param>
        public DataTable(System.Type type, string name)
        {
            this.BeginInit();
            InitDataTable(this, type, name);
            this.EndInit();
        }
        #endregion

        #region Common property 
        private bool clonal = false;
        /// <summary>
        /// Use same structure of mode to create Datatable.
        /// </summary>
        public bool Clonal
        {
            get
            {
                return this.clonal;
            }
        }
        #endregion
    }
}
